package com.demo.chapter6collect;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.IntStream;

//Integer：流中元素类型
//Map<Boolean, List<Integer>>：累加器类型
//Map<Boolean, List<Integer>>：collect操作的结果类型
public class SelfCollector implements Collector<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>>{

	/**判断是否是质数
	 * @param primes：已经被检测出来的质数列表
	 * @param candidate：候选数
	 * @return
	 */
	private boolean isPrime(List<Integer> primes, int candidate){
		int candaditeRoot = (int)Math.sqrt((double)candidate);
		return takeWhile(primes, i -> i <= candaditeRoot).stream().noneMatch(i -> candidate % i == 0);
	}
	
	/**只需要对小于候选数平方根的质数进行检测就可以了
	 * @param primes：已经被检测出来的质数列表
	 * @param p：列表里的值是否小于候选数的平方根
	 * @return
	 */
	private List<Integer> takeWhile(List<Integer> primes, Predicate<Integer> p){
		int i = 0;
		for (Integer item : primes) {
			if(!p.test(item)){
				return primes.subList(0, i);
			}
			i++;
		}
		return primes;
	}
	
	@Override
	//建立新的结果容器，供数据收集过程使用
	public Supplier<Map<Boolean, List<Integer>>> supplier() {
		return () -> new HashMap<Boolean, List<Integer>>(){{
			put(true, new ArrayList<Integer>());
			put(false, new ArrayList<Integer>());
		}};
	}

	@Override
	//将元素添加到结果容器，两个参数：1、保存归约结果的累加器(已收集了流中的前n-1个项目)，2、第n个元素本身
	public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
		return (acc, candidate) -> {
			acc.get(isPrime(acc.get(true), candidate)).add(candidate);
		};
	}

	@Override
	//合并两个容器，修改第一个累加器，将其与第二个累加器的内容合并，返回修改后的第一个累加器
	public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
		//这个收集器是不能并行的，所以该方法永远不会执行
		return (mp1, mp2) -> {
			mp1.get(true).addAll(mp2.get(true));
			mp1.get(false).addAll(mp2.get(false));
			return mp1;
		};
	}

	@Override
	//对结果容器应用最终转换，此例中累加器对象恰好符合预期的最终结果
	public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
		return Function.identity();
	}

	@Override
	public Set<java.util.stream.Collector.Characteristics> characteristics() {
		return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
	}
	
	private static Map<Boolean, List<Integer>> partitionPrimesWithCustomCollector(int candidate){
		return IntStream.rangeClosed(2, candidate).boxed().collect(new SelfCollector());
	}
	
	public static void main(String[] args) {
		System.out.println(partitionPrimesWithCustomCollector(100));
	}

}
